#include "estructuras.h"
#include <time.h>

/*
 * Este proceso inicia el circuito con un Kanban de Produccion y un Kanban entre procesos.
 * Se envian tantos Kanban entre procesos como partes necesito.
 * Tengo las siguientes colas:
 * 				1. Interna: utilizada para llevar el stock a pie de maquina
 *				2. Externa: para interactuar con Body Shop
 */
int main(int argc, char *argv[])
{
	srand(time(NULL));				/* Semilla para que que la funcion random pueda variar */
	char mensaje[120];
	m_kanbanproduccion msg_kproduccion;
	m_kanbanentreprocesos msg_kprocesos_local;	/* Kanban entre procesos para llenar el stock inicial */
	m_kanbanentreprocesos msg_kprocesos;		/* Kanban entre procesos para solicitar stock a Body Shop */
	m_kanbanentreprocesos msg_kprocesos_recibido;	/* Kanban entre procesos para recibir los que me devuelve Body Shop */
	t_stock stock;
	int colaid;
	key_t clave_cola;
	int i;

	/* Defino la estructura del stock */
	stock.stock = 12;				/* Cantidad de stock que puedo almacenar */
	stock.stockMinimo = 5;
	stock.stockLibre = rand()%stock.stock + 1;
	stock.estado = 0;				/* 0 sin Kanban Proveedor, 1 con Kanban Proveedor */				

	/* Obtengo la clave de la cola */
	clave_cola = ftok(DIRECTORIO, COLA_EXTERNA);

	if ( (colaid = msgget(clave_cola, 0666)) < 0 )								/* Obtengo el ID de la cola */
	{
		sprintf(mensaje, "Error al obtener el ID de la cola Externa\n");
		write(fileno(stdout), mensaje, strlen(mensaje));

		exit(-1);
	}

	printf("+-------------------------+\n");
	printf("| Generando stock inicial |\n");
	printf("+-------------------------+\n");
	printf("Tamanio de stock: %d\n", stock.stock);
	printf("Stock minimo: %d\n", stock.stockMinimo);
	printf("Stock libre: %d\n", stock.stockLibre);
	printf("\n");

	/*
		Como es la primera vez que ejecuto, creo las partes que tengo actualmente en stock, simplemente
		poniendolas en la cola para ir sacandolas en orden y mantener uniformidad con los id's
	*/

	/* El Kanban entre procesos es el que termino usando para representar las partes que tengo actualmente en stock */
	msg_kprocesos_local.mtype = MSG_PAINTSHOP;
	msg_kprocesos_local.nroSector = getpid();
	msg_kprocesos_local.nroVehiculo = rand()%9999 + 1;
	msg_kprocesos_local.codParte = 0;
	msg_kprocesos_local.nroOrden = 0;

	for ( i = 1; i <= (stock.stock - stock.stockLibre); i++)
	{
		if ( msgsnd(colaid, (m_kanbanentreprocesos *) &msg_kprocesos_local, sizeof(m_kanbanentreprocesos), 0) < 0 )	
		{
			sprintf(mensaje, "Error al guardar la pieza nro. %d en el stock\n", msg_kprocesos_local.nroVehiculo);
			write(fileno(stdout), mensaje, strlen(mensaje));

			exit(-1);
		}

		printf("Nro. de Vehiculo: %d\n", msg_kprocesos_local.nroVehiculo);

		/* Incremento el numero de vehiculo */
		msg_kprocesos_local.nroVehiculo++;
	}


	/* Armo los mensajes que voy a pasar a Body Shop
		1. Kanban de Produccion
		2. Kanban entre Procesos
	*/
	msg_kproduccion.mtype = MSG_ARMADO_PROD;
	msg_kproduccion.ventas = rand()%9999 + 1;
	msg_kproduccion.sector = getpid();
	msg_kproduccion.nroInicial = 1;
	msg_kproduccion.cantVehiculos = rand()%10 + 12;
	msg_kproduccion.sectorSiguiente = 0;
	msg_kproduccion.cantidad = 0;

	msg_kprocesos.mtype = MSG_ARMADO_PROC;
	msg_kprocesos.nroSector = getpid();
	msg_kprocesos.nroVehiculo = msg_kprocesos_local.nroVehiculo;		/* Uso el ultimo numero de vehiculo que cargue en stock */
	msg_kprocesos.codParte = 0;
	msg_kprocesos.nroOrden = 0;

  while(1)
  {
	/* Envio a Body Shop el Kanban de produccion */
	if ( msgsnd(colaid, (m_kanbanproduccion *) &msg_kproduccion, sizeof(m_kanbanproduccion), 0) < 0 )	/* Meto el pedido en la cola */	
	{
		sprintf(mensaje, "Error al encolar el Kanban de produccion\n");
		write(fileno(stdout), mensaje, strlen(mensaje));

		exit(-1);
	}

	printf("+----------------------------------------------------+\n");
	printf("| Se envio kanban de produccion a BodyShop -> armado |\n");
	printf("| - ID Ventas: %ld\n", msg_kproduccion.ventas);
	printf("| - ID Pain Shop: %ld\n", msg_kproduccion.sector);
	printf("| - Cantidad Vehiculos: %d\n", msg_kproduccion.cantVehiculos);
	printf("+----------------------------------------------------+\n");
	printf("\n");
	printf("Espacio disponible en stock: %d\n", stock.stockLibre);
	printf("\n");

	/*
	 * Emito tantos Kanban entre procesos como espacios libres en stock tengo, para que Body Shop
	 * vaya produciendo las partes y me las mande a medida que las tien listas
	 */
	int kproce_solicitados;			/* Cuento la cantidad de Kanban entre procesos que emiti */
	int a_producir;				/* Cantidad de partes que voy a pedir */
	
	if ( stock.stockLibre > msg_kproduccion.cantVehiculos)
	{
		a_producir = msg_kproduccion.cantVehiculos;
	} else {
		a_producir = stock.stockLibre;
	}

	/* Solicito tantas partes como stock disponible tengo pero no mas que la cantidad de autos que voy a pintar */
	for ( kproce_solicitados = 1; kproce_solicitados <= a_producir; kproce_solicitados++)
	{
		if ( msgsnd(colaid, (m_kanbanentreprocesos *) &msg_kprocesos, sizeof(m_kanbanentreprocesos), 0) < 0 )	
		{
			sprintf(mensaje, "Error al encolar el Kanban entre procesos\n");
			write(fileno(stdout), mensaje, strlen(mensaje));

			exit(-1);
		}

		printf("---------------------------------------------------\n");
		printf("Mensaje %d de %d\n", kproce_solicitados, stock.stockLibre);
		printf("Se envio kanban entre procesos a BodyShop -> armado\n");
		printf("Nro. de Vehiculo: %d\n", msg_kprocesos.nroVehiculo);
		printf("Sector: %ld\n", msg_kprocesos.nroSector);
		printf("Codigo de Parte: %d\n", msg_kprocesos.codParte);

		/* Incremento el numero de vehiculo */
		msg_kprocesos.nroVehiculo++;
	}

	/* 
		Como Body Shop me pasa la estructura completa del vehiculo yo necesito 1 sola parte por c/u y por lo tanto,
		emito tantos Kanban de procesos como vehiculos me pidieron.
	*/
	int cant_partes = msg_kproduccion.cantVehiculos;		/* 1 parte = 1 auto */

	for ( i = 1; i <= cant_partes; i++)
	{
		/* Si el stock disponible es cero, me bloqueo esperando una parte */
		if ( stock.stockLibre == stock.stock )
		{
			printf("No tengo piezas para seguir produciendo, espero las partes de Body Shop\n");
			if ( msgrcv(colaid, (m_kanbanentreprocesos *) &msg_kprocesos_recibido, sizeof(m_kanbanentreprocesos), msg_kproduccion.sector, 0) < 0 )
			{
				sprintf(mensaje, "Error al recibir el Kanban entre procesos con armado\n");
				write(fileno(stdout), mensaje, strlen(mensaje));

				exit(-1);
			}

			printf("Recibi una pieza de Body Shop\n");
			printf("Nro. de Vehiculo: %d\n", msg_kprocesos_recibido.nroVehiculo);
			/* Si recibo una pieza, incremento las partes del stock, por lo tanto se me achica el espacio libre */
			stock.stockLibre--;
			printf("Espacio disponible en stock: %d\n", stock.stockLibre);
			printf("\n");

			/* Meto la pieza que recibi en mi stock */
			msg_kprocesos_local.mtype = MSG_PAINTSHOP;
			msg_kprocesos_local.nroSector = msg_kprocesos_recibido.nroSector;
			msg_kprocesos_local.nroVehiculo = msg_kprocesos_recibido.nroVehiculo;
			msg_kprocesos_local.codParte = msg_kprocesos_recibido.codParte;
			msg_kprocesos_local.nroOrden = msg_kprocesos_recibido.nroOrden;

			if ( msgsnd(colaid, (m_kanbanentreprocesos *) &msg_kprocesos_local, sizeof(m_kanbanentreprocesos), 0) < 0 )	
			{
				sprintf(mensaje, "Error al guardar la pieza nro. %d en el stock\n", msg_kprocesos_local.nroVehiculo);
				write(fileno(stdout), mensaje, strlen(mensaje));

				exit(-1);
			}
		}

		printf("+--------------------------------+\n");
		printf("| Recibiendo piezas de Body Shop |\n");
		printf("+--------------------------------+\n");

		/* Recibo todos las partes que me puede haber enviado Body Shop */
		while ( msgrcv(colaid, (m_kanbanentreprocesos *) &msg_kprocesos_recibido, sizeof(m_kanbanentreprocesos), msg_kproduccion.sector, IPC_NOWAIT) != -1 )
		{
			printf("Nro. de Vehiculo: %d\n", msg_kprocesos_recibido.nroVehiculo);
			printf("Sector: %ld\n", msg_kprocesos_recibido.nroSector);
			/* Si recibo una pieza, incremento las partes del stock, por lo tanto se me achica el espacio libre */
			stock.stockLibre--;
			printf("Espacio disponible en stock: %d\n", stock.stockLibre);
			printf("\n");

			/* Meto la pieza que recibi en mi stock */
			msg_kprocesos_local.mtype = MSG_PAINTSHOP;
			msg_kprocesos_local.nroSector = msg_kprocesos_recibido.nroSector;
			msg_kprocesos_local.nroVehiculo = msg_kprocesos_recibido.nroVehiculo;
			msg_kprocesos_local.codParte = msg_kprocesos_recibido.codParte;
			msg_kprocesos_local.nroOrden = msg_kprocesos_recibido.nroOrden;

			if ( msgsnd(colaid, (m_kanbanentreprocesos *) &msg_kprocesos_local, sizeof(m_kanbanentreprocesos), 0) < 0 )	
			{
				sprintf(mensaje, "Error al guardar la pieza nro. %d en el stock\n", msg_kprocesos_local.nroVehiculo);
				write(fileno(stdout), mensaje, strlen(mensaje));

				exit(-1);
			}
		}

		printf("+-------------------+\n");
		printf("| Pintando vehiculo |\n");
		printf("+-------------------+\n");

		/* Saco una pieza de mi stock */
		if ( msgrcv(colaid, (m_kanbanentreprocesos *) &msg_kprocesos_recibido, sizeof(m_kanbanentreprocesos), MSG_PAINTSHOP, 0) < 0 )
		{
			sprintf(mensaje, "Error al sacar una pieza del stock\n");
			write(fileno(stdout), mensaje, strlen(mensaje));

			exit(-1);
		}

		/* Comienzo a producir */
		printf("Pintando vehiculo %d de %d\n", i, msg_kproduccion.cantVehiculos);
		printf("Nro. de Vehiculo: %d\n", msg_kprocesos_recibido.nroVehiculo);
		sleep(rand()%20);

		/* Saco una pieza del stock, por lo que tengo un lugar mas libre */
		stock.stockLibre++;

		printf("Espacio disponible en stock: %d\n", stock.stockLibre);
		printf("\n");

		/*
			Si ya pinte tantos autos como Kanban entre procesos emiti entonces comienzo a emitir kanbans
			nuevamente para completar el stock.
		*/
		if ( kproce_solicitados > 0 )
		{
			/* Resto uno a la cantidad de Kanban entre procesos solicitados anteriormente */
			kproce_solicitados--;

		} else {
			msg_kprocesos.mtype = MSG_ARMADO_PROC;
			msg_kprocesos.nroSector = getpid();
			msg_kprocesos.nroVehiculo = msg_kprocesos_local.nroVehiculo;	/* Uso el ultimo numero de vehiculo que cargue en stock */
			msg_kprocesos.codParte = 0;
			msg_kprocesos.nroOrden = 0;

			/* Emito un Kanban entre procesos para reponer la pieza que use */
			if ( msgsnd(colaid, (m_kanbanentreprocesos *) &msg_kprocesos, sizeof(m_kanbanentreprocesos), 0) < 0 )	
			{
				sprintf(mensaje, "Error al encolar el Kanban entre procesos\n");
				write(fileno(stdout), mensaje, strlen(mensaje));

				exit(-1);
			}
			/* Incremento el numero de vehiculo para poder emitir otro Kanban entre procesos distinto */
			msg_kprocesos.nroVehiculo++;
			printf("Se envio kanban entre procesos a BodyShop -> armado\n");
			printf("Nro. de Vehiculo: %d\n", msg_kprocesos.nroVehiculo);
			printf("Sector: %ld\n", msg_kprocesos.nroSector);
			printf("Codigo de Parte: %d\n", msg_kprocesos.codParte);
			printf("\n");
		}
	} /* Fin for cant_partes */
  } /* Fin while(1) */

 return 0;
}
